<?php
// @formatter:off
/**
 * @file WCProfile.php
 * @author Alejandro Dario Simi
 * @date $Date: 2013-08-05 00:26:28 +0000 (Mon, 05 Aug 2013) $
 *
 * $Id: WCProfile.php 100 2013-08-05 00:26:28Z daemonraco@gmail.com $
 * $URL: http://wcomix.googlecode.com/svn/tags/wcomix-1.0.0.2/includes/security/WCProfile.php $
 */
// @formatter:on

/**
 * @class WCProfile This class holds all the logic to manage grants belonging to
 * a profile and a user.
 */
class WCProfile {
	/**
	 * @var string This is the code name of current profile.
	 */
	protected $_code = false;
	/**
	 * @var int[] List if permission codes given to this profile.
	 */
	protected $_grants = array();
	/**
	 * @var id[] List of available group ids for this profile.
	 */
	protected $_grantedGroups = false;
	/**
	 * @var WCUser Pointer to the user used to load this profile. A null
	 * value means this object wasn't loaded using a user pointer.
	 */
	protected $_user = null;
	//
	// Public methods.
	/**
	 * Checks a list of permission codes for any grant.
	 *
	 * @param int[] ... This method doesn't have a fixed amount of parameter,
	 * but they all must be permission codes.
	 * @return boolean Returns true when any of the asked permission is
	 * granted. When no permission is asked, returns false.
	 */
	public function allowedAny() {
		//
		// Setting a default value to be returned.
		$allowed = false;
		//
		// Checking all asked parameters.
		foreach(func_get_args() as $perm) {
			//
			// Enforcing numeric type.
			$perm = $perm + 0;
			//
			// Checking grants.
			if($this->granted($perm)) {
				//
				// At this pointer, user has some off the
				// requested permissions.
				$allowed = true;
				break;
			}
		}
		//
		// Returning permissions' check results.
		return $allowed;
	}
	/**
	 * Checks a list of permission codes.
	 *
	 * @param int[] ... This method doesn't have a fixed amount of parameter,
	 * but they all must be permission codes.
	 * @return boolean Returns true when all asked permission are granted.
	 * When no permission is asked, returns false.
	 */
	public function allowedTo() {
		//
		// Setting a default value to be returned.
		$allowed = false;
		//
		// ancillary flag for permissions check operation.
		$first = true;
		//
		// Checking all asked parameters.
		foreach(func_get_args() as $perm) {
			//
			// Enforcing numeric type.
			$perm = $perm + 0;
			//
			// Checking grants.
			$allowed = ($allowed || $first) && $this->granted($perm);
			$first = false;
		}
		//
		// Returning permissions' check results.
		return $allowed;
	}
	/**
	 * This method allows to get the code name of this profile.
	 *
	 * @return string Returns a code name.
	 */
	public function code() {
		return $this->_code;
	}
	/**
	 * This method checks a specific permission.
	 *
	 * @return boolean Returns true if the user is granted for this
	 * permission.
	 */
	public function granted($perm) {
		//
		// If it's a root user, it always is allowed, otherwise, it
		// checks the list of permissions.
		return $this->code() == "ROOT" || in_array($perm, $this->_grants);
	}
	/**
	 * This method checks a grants over a specific group.
	 *
	 * @param WCGroup $group Group to be checked.
	 * @return boolean Returns true if the user is granted for this
	 * permission.
	 */
	public function grantedGroup(WCGroup &$group) {
		//
		// If it's a root user, it always is allowed, otherwise, it
		// checks the list of permissions. Also, if it a public group
		// it's allowed to.
		return $this->code() == "ROOT" || $group->isPublic() || in_array($group->id, $this->_grantedGroups);
	}
	/**
	 * This method loads this profile object based on a user.
	 *
	 * @param WCUser $user Pointer to the user to load. When null, it loads
	 * a default profile given by '$wcPermissions["default"]'.
	 */
	public function load(WCUser &$user = null) {
		//
		// Loading global pointer.
		global $wcPermissions;
		//
		// Checking if there's an user specified.
		if($user == null) {
			//
			// At this point, no user was specified, therefore the
			// internal pointer to it should remain null.
			$this->_user = null;
			//
			// Setting default profile code.
			$this->_code = $wcPermissions["default"];
		} else {
			//
			// At this point a user was given. Saving a pointer to
			// it.
			$this->_user = $user;
			//
			// Saving the user's profile code.
			$this->_code = $user->profileCode();
			//
			// List of root user ids.
			$roots = array(
				WC_USER_ROOT_ID,
				WC_USER_CRON_ID
			);
			//
			// Checking if a non root user is having a root profile.
			if($this->code() == "ROOT" && !in_array($user->id, $roots)) {
				//
				// wcomix supports some specific id as root
				// users. When other users have this profile code
				// they fall to the next name in the profiles
				// hierarchy.
				// If there's nothing to fall into, they get a
				// profile called '*' (asterisk).
				$this->_code = isset($wcPermissions["pyramid"]["ROOT"]) ? $wcPermissions["pyramid"]["ROOT"] : "*";
			} elseif(in_array($user->id, $roots)) {
				//
				// At this point, the user is a root (based on
				// its id) therefore it must have a root profile.
				$this->_code = "ROOT";
			}
		}
		//
		// Loading available groups.
		$this->loadGroups();
		//
		// If this is root profile is not necessary to load permissions.
		if($this->code() != "ROOT") {
			//
			// At this point, this is not a root profile and
			// permissions have to be loaded based on it code.
			$this->loadPermissions($this->code());
		}
	}
	/**
	 * This method allows to get the name of this profile.
	 *
	 * @return string Returns a name.
	 */
	public function name() {
		return $this->code();
	}
	//
	// Protected methods.
	/**
	 * This method loads the list of available groups.
	 */
	protected function loadGroups() {
		//
		// Checking if available groups are already loaded.
		if($this->_grantedGroups === false) {
			//
			// Creating an empty list to store available groups.
			$this->_grantedGroups = array();
			//
			// Checking if theres a user pointer defined and if it
			// points to a valid user.
			if($this->_user && $this->_user->ok()) {
				//
				// Loading global pointer.
				global $wcGroupsHolder;
				//
				// Walking over al groups in the system.
				foreach($wcGroupsHolder->groups() as $group) {
					//
					// Checking condition to consider this
					// group as available:
					//	- is this a root profile?
					//	- is a public group?
					//	- is the user something more
					//	  than an anonymous user for the
					//	  group.
					if($this->code() == "ROOT" || $group->isPublic() || $this->_user->profileCode($group) != 'ANON') {
						$this->_grantedGroups[] = $group->id;
					}
				}
			}
		}
	}
	/**
	 * This method loads all permissions of certain profile code.
	 *
	 * @param string $code Profile code to be searched.
	 */
	protected function loadPermissions($code) {
		//
		// Loading global pointer.
		global $wcPermissions;
		//
		// Loading more permissions based on profile code hierarchy.
		$this->loadPyramidPermissions($code);
		//
		// Merging and cleaning loaded permissions to avoid duplicates.
		$this->_grants = array_unique(array_merge($this->_grants, $wcPermissions["direct-perms"][$code]));
	}
	/**
	 * This method recursively loads permissions base on the profile code's
	 * hierarchy.
	 *
	 * @param string $code This is the code where the hierarchy load should
	 * start.
	 */
	protected function loadPyramidPermissions($code) {
		//
		// Loading global pointer.
		global $wcPermissions;
		//
		// Merging and cleaning loaded permissions to avoid duplicates.
		$this->_grants = array_unique(array_merge($this->_grants, $wcPermissions["pyramid-perms"][$code]));
		//
		// If there's a sub-code defined in the hierarchy, it is loaded
		// too.
		if(isset($wcPermissions["pyramid"][$code])) {
			//
			// Recursive call.
			$this->loadPermissions($wcPermissions["pyramid"][$code]);
		}
	}
}
?>